/*
 * Created by Wildish on 2016-10-31
 *
 * Contact me with keithknight@qq.com
 *
 * Copyright (c) 2016 Wildish
 */

package com.wildish.hybridframework.core;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.webkit.WebView;

import com.liulishuo.filedownloader.FileDownloader;
import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
import com.nostra13.universalimageloader.cache.memory.impl.WeakMemoryCache;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;
import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer;
import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
import com.wildish.hybridframework.R;
import com.wildish.hybridframework.activity.WebViewActivity;
import com.wildish.hybridframework.jsbinding.HybridSchemeActivity;
import com.wildish.hybridframework.jsbinding.proxy.DataHandler;
import com.wildish.hybridframework.jsbinding.proxy.DefaultHybridProxy;
import com.wildish.hybridframework.jsbinding.proxy.HybridProxy;
import com.wildish.hybridframework.jsbinding.proxy.HybridProxyManager;
import com.wildish.hybridframework.jsbinding.webview.WebPageIntent;
import com.wildish.hybridframework.jsbinding.webview.WebViewPage;
import com.wildish.hybridframework.utils.Logger;
import com.wildish.hybridframework.utils.audio.MediaPlayerHelper;
import com.wildish.hybridframework.utils.file.FileUtil;

import org.apache.commons.lang3.StringUtils;
import org.json.JSONObject;

import java.io.File;
import java.util.Stack;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class HybridGlobal {

    //
    private static HybridGlobal instance;
    private static Boolean initialize = false;
    private Context context;
    public static Logger logger;
    private SharedPreferences globalSp;
    public static Stack<WebViewPage> webViewStack = new Stack<>();
    private MediaPlayerHelper soundHelper;
    private AudioManager mAudioManager;

    public static String CUSTOM_SCHEME;
    public static String IMAGESIZE_ARRAY;

    private static File baseFolder;         // /data/data/{package}/file
    private static File fileFolder;         // {baseFolder}/file
    private static File webRootFolder;      // {baseFolder}/webroot
    private static File webRootCacheFolder; // {baseFolder}/webroot/cache
    private static File externalBaseFolder; // /sdcard/{package}
    private static File tempFolder;         // {externalBaseFolder}/temp

    private static final String WEBROOT_FOLDER = "webroot";
    private static final String GLOBAL_SP = "HYBIRDFRAMEWORK_GLOBAL";
    private static final String GLOBAL_BASE_FOLDER = "global_base_folder";
    private static final String GLOBAL_EXTERNAL_BASE_FOLDER = "global_external_base_folder";
    public static final String ACTION_HYBRID_SCHEME_ACTION = "com.wildish.hybirdframework.CUSTOM_SCHEME";
    public static final String PROXY_HF_DEFAULT = "proxy_default";

    public static final ExecutorService pool = Executors.newFixedThreadPool(5);


    public static HybridGlobal getInstance() {
        if(instance == null) {
            instance = new HybridGlobal();
        }
        return instance;
    }

    private BroadcastReceiver dynamicReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            intent.setClassName(context.getPackageName(), HybridSchemeActivity.class.getName());
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent);
        }
    };

    /**
     * application中调用，初始化环境
     * @param context
     */
    public void initHybridGlobal(Context context, String scheme) {
        this.context = context;
        createBaseFolder();

        logger = new Logger(getExternalBaseFolder().getAbsolutePath());
        logger.setTarget(Logger.Debug, Logger.Fatal);

        HybridGlobal.CUSTOM_SCHEME = scheme;

        // 动态注册
        IntentFilter customFilter = new IntentFilter();
        customFilter.addAction(ACTION_HYBRID_SCHEME_ACTION);
        customFilter.addCategory(Intent.CATEGORY_DEFAULT);
        customFilter.addCategory(Intent.CATEGORY_BROWSABLE);
        customFilter.addDataScheme(HybridGlobal.CUSTOM_SCHEME);
        context.registerReceiver(dynamicReceiver, customFilter);

        // 注册代理
        HybridProxyManager.getInstance().addProxy(new DefaultHybridProxy(PROXY_HF_DEFAULT));

        // 初始化全局downloader
        FileDownloader.init(context);

        // 注册全局ImageLoader
        initImageLoader(context);
    }

    public void setDataHandler(DataHandler dataHandler) {
        HybridProxyManager.getInstance().getDefaultProxy().setDataHandler(dataHandler);
    }

    public SharedPreferences getGlobalSp() {
        if (globalSp == null && context != null) {
            globalSp = this.context.getSharedPreferences(GLOBAL_SP, Context.MODE_PRIVATE);
        }
        return globalSp;
    }

    public static File getBaseFolder() {
        return baseFolder;
    }
    public static File getExternalBaseFolder() {
        return externalBaseFolder;
    }
    public static File getWebRootFolder() {
        if(webRootFolder ==  null) {
            webRootFolder = new File(baseFolder, WEBROOT_FOLDER);
            webRootFolder.mkdirs();
            if(webRootFolder.exists()) {
                createNoMedia(webRootFolder);
            }
        }
        return webRootFolder;
    }
    public static File getWebRootCacheFolder() {
        if (webRootCacheFolder == null) {
            webRootCacheFolder = new File(webRootFolder, "cache");
            webRootCacheFolder.mkdirs();
            File createNoMedia = new File(webRootCacheFolder, ".nomedia");
            try {
                createNoMedia.createNewFile();
            } catch (Exception e) {
            }
        }
        return webRootCacheFolder;
    }
    public static File getFileFolder() {
        if (fileFolder == null) {
            fileFolder = new File(baseFolder, "file");
            fileFolder.mkdirs();
        }
        return fileFolder;
    }

    public static File getTempFolder() {
        if (tempFolder == null) {
            tempFolder = new File(externalBaseFolder, "temp");

            if (tempFolder.exists()) {
                FileUtil.delDir(tempFolder);
            }
            tempFolder.mkdirs();
            createNoMedia(tempFolder);
        }

        return tempFolder;
    }

    /**
     * support method
     */
    public void initImageLoader(Context context) {
        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
                .memoryCacheExtraOptions(1280, 960) //即保存的每个缓存文件的最大宽高
                .threadPoolSize(5) //线程池内加载的数量
                .threadPriority(Thread.NORM_PRIORITY - 2) //解释：当同一个Uri获取不同大小的图片，缓存到内存时，只缓存一个。默认会缓存多个不同的大小的相同图片
//                .denyCacheImageMultipleSizesInMemory()  //拒绝缓存多个图片。
                .memoryCache(new WeakMemoryCache()) //缓存策略你可以通过自己的内存缓存实现 ，这里用弱引用，缺点是太容易被回收了，不是很好！
                .memoryCacheSize(10 * 1024 * 1024) //设置内存缓存的大小
                .diskCacheSize(10 * 1024 * 1024) //设置磁盘缓存大小
                .diskCacheFileNameGenerator(new Md5FileNameGenerator()) //将保存的时候的URI名称用MD5 加密
                .tasksProcessingOrder(QueueProcessingType.LIFO) //设置图片下载和显示的工作队列排序
                .diskCacheFileCount(100) //缓存的文件数量
                .diskCache(new com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache(HybridGlobal.getTempFolder())) //自定义缓存路径
                .defaultDisplayImageOptions(getDisplayOptions()) //显示图片的参数，默认：DisplayImageOptions.createSimple()
                .imageDownloader(new BaseImageDownloader(context, 30 * 1000, 30 * 1000)) // connectTimeout (5 s), readTimeout (30 s)超时时间
                .build();//开始构建
        ImageLoader.getInstance().init(config);
    }

    private DisplayImageOptions getDisplayOptions() {
        DisplayImageOptions options;
        options = new DisplayImageOptions.Builder().showImageOnLoading(R.drawable.loading01) // 设置图片在下载期间显示的图片
                .showImageForEmptyUri(R.drawable.failed01)// 设置图片Uri为空或是错误的时候显示的图片
                .showImageOnFail(R.drawable.failed01) // 设置图片加载/解码过程中错误时候显示的图片
                .cacheInMemory(true)// 设置下载的图片是否缓存在内存中
                .considerExifParams(true) // 是否考虑JPEG图像EXIF参数（旋转，翻转）
                .imageScaleType(ImageScaleType.EXACTLY_STRETCHED)// 设置图片以如何的编码方式显示
                .bitmapConfig(Bitmap.Config.RGB_565)// 设置图片的解码类型//
                .resetViewBeforeLoading(true)// 设置图片在下载前是否重置，复位
                .displayer(new RoundedBitmapDisplayer(20))// 是否设置为圆角，弧度为多少
                .displayer(new FadeInBitmapDisplayer(100))// 是否图片加载好后渐入的动画时间
                .build();// 构建完成
        return options;
    }

    public void updateGallery() {
        Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        Uri uri = Uri.fromFile(HybridGlobal.getBaseFolder());
        intent.setData(uri);
        this.context.sendBroadcast(intent);
    }

    private static void createNoMedia(File folder) {
        try{
            File createNoMedia = new File(folder, ".nomedia");
            createNoMedia.createNewFile();
        } catch(Exception e) {}
    }

    private void createBaseFolder() {
        SharedPreferences globalSp = getGlobalSp();
        if (baseFolder == null) {
            String baseFolderPath = globalSp.getString(GLOBAL_BASE_FOLDER, "");
            if (StringUtils.isNotBlank(baseFolderPath)) {
                baseFolder = new File(baseFolderPath);
            } else {
                baseFolder = context.getFilesDir();

                if (!baseFolder.exists()) {
                    baseFolder.mkdirs();
                }

                globalSp.edit()
                        .putString(GLOBAL_BASE_FOLDER, baseFolder.getAbsolutePath())
                        .apply();
            }

            String externalBaseFolderPath = globalSp.getString(GLOBAL_EXTERNAL_BASE_FOLDER, "");
            if (StringUtils.isNotBlank(externalBaseFolderPath)) {
                externalBaseFolder = new File(externalBaseFolderPath);
            } else {
                boolean sdCardExist = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
                if (sdCardExist) {
                    externalBaseFolder = new File(Environment.getExternalStorageDirectory(), context.getPackageName());
                } else {
                    externalBaseFolder = new File(Environment.getDataDirectory(), context.getPackageName());
                }
                if (!externalBaseFolder.exists()) {
                    externalBaseFolder.mkdirs();
                }
                globalSp.edit()
                        .putString(GLOBAL_EXTERNAL_BASE_FOLDER, externalBaseFolder.getAbsolutePath())
                        .apply();
            }
        }
    }

    public static void addWebViewPage(WebViewPage page) {
        webViewStack.push(page);
    }

    public static void addWebViewPage(Activity context, WebView webView, String typeTag) {
        addWebViewPage(new WebViewPage(context, webView, typeTag));
    }

    /**
     * 获取当前展示的webview
     * @return
     */
    public static WebView getCurrentWebView() {
        if(!webViewStack.isEmpty()) {
            WebViewPage webViewPage =  webViewStack.peek();
            return webViewPage.getWebView();
        } else {
            return null;
        }
    }

    /**
     * 获取当前webview的context
     * @return
     */
    public static Activity getCurrentWebViewContext() {
        if(!webViewStack.isEmpty()) {
            WebViewPage webViewPage = webViewStack.peek();
            return webViewPage.getContext();
        } else {
            return null;
        }
    }

    public String getVersionInfo() {
        JSONObject version = new JSONObject();
        try {
            version.put("version_name", this.getVersionName());
            version.put("version_code", this.getVersionCode());
        } catch (Exception e) {

        }
        return version.toString();
    }
    public Integer getVersionCode() {
        try {
            PackageInfo pi = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
            return pi.versionCode;
        } catch (Exception e) {
            return 0;
        }
    }
    public String getVersionName() {
        try {
            PackageInfo pi = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
            return pi.versionName;
        } catch (Exception e) {
            return "";
        }
    }

    public MediaPlayerHelper getSoundHelper() {
        if (soundHelper == null) {
            soundHelper = new MediaPlayerHelper(context);
        }

        return soundHelper;
    }

    public static String getCustomScheme() {
        return CUSTOM_SCHEME;
    }

    public static void setCustomScheme(String scheme) {
        CUSTOM_SCHEME = scheme;
    }

    public static void showPage(Context context, WebPageIntent pageIntent) {
        Bundle bundle = new Bundle();
        bundle.putString("project", pageIntent.getProject());
        bundle.putString("typeTag", pageIntent.getPageType());

        if(StringUtils.isNotBlank(pageIntent.getPage())
            || StringUtils.isNotBlank(pageIntent.getModuleName())) {
            bundle.putString("page", pageIntent.getProject() + pageIntent.getPage());
            JSONObject params = pageIntent.getParams();
            if(params == null) {
                params = new JSONObject();
            }
            try{
                params.put("moduleName", pageIntent.getModuleName());
            } catch (Exception e) {
                HybridGlobal.logger.log(e);
            }
            bundle.putString("paramsdata", params.toString());
        }

        Intent intent = new Intent(context, WebViewActivity.class);
        intent.putExtras(bundle);
        context.startActivity(intent);
    }

    public static String getImageFilePath(String fileUrl, int width) {
        if (!fileUrl.contains(".")) {
            HybridGlobal.logger.log("错误的请求路径：" + fileUrl);
            return "";
        }

        if (width == 0 || StringUtils.isBlank(HybridGlobal.IMAGESIZE_ARRAY)) {
            return fileUrl;
        }
        String[] imageSizeArray = HybridGlobal.IMAGESIZE_ARRAY.split(",");
        int finalWidth = 0;
        for (int i = 0; i != imageSizeArray.length; i++) {
            if (width < Integer.valueOf(imageSizeArray[i])) {
                finalWidth = Integer.valueOf(imageSizeArray[i]);
                break;
            }
        }
        if (finalWidth == 0) {
            finalWidth = Integer.valueOf(imageSizeArray[imageSizeArray.length - 1]);
        }

        return fileUrl.substring(0, fileUrl.lastIndexOf(".")) + "_" + finalWidth + fileUrl.substring(fileUrl.lastIndexOf("."));
    }

    public static boolean isInit() {
        return initialize;
    }

    public String getPackageName() {
        return context.getPackageName();
    }

    public void closeMediaVoice() {
        if (mAudioManager == null) {
            mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        }
        mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 0, 0);
    }

    public void openMediaVoice() {
        if (mAudioManager == null) {
            mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        }
        int max = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, max, 0);
    }

    public void addProxy(HybridProxy proxy) {
        HybridProxyManager.getInstance().addProxy(proxy);
    }
}
